#ifndef ENTITY_H
#define ENTITY_H

#include"functions.h"
#include <vector>
#include <ostream>
#include <string>
using std::vector;
using std::ostream;
using std::string;

namespace entity {
    class KeyValue
    {
    public:
        int id;
        string value;
        int ref;

        KeyValue() : id(0), ref(0) {}

        bool operator<(KeyValue& c)
        {
            return this->id < c.id;
        }

        bool operator==(KeyValue& c)
        {
            return this->id == c.id;
        }

        friend ostream& operator<<(ostream& os, const KeyValue& kv);
    };

    ostream& operator<<(ostream& os, const KeyValue& kv)
    {
        os << "id:" << kv.id << "\tvalue:" << kv.value;
        return os;
    }

    class Record
    {
    public:
        int id;
        vector<KeyValue> keys;
        vector<KeyValue> accounts;
        KeyValue password;

        Record() : id(0) {}

        bool operator<(Record& c)
        {
            return this->id < c.id;
        }

        bool operator==(Record& c)
        {
            return this->id == c.id;
        }

        friend ostream& operator<<(ostream& os, const Record& r);
    };

    ostream& operator<<(ostream& os, const Record& r)
    {
        os << "id:" << r.id
            << "\nkeys:";
        for (auto& i : r.keys)
        {
            os << i.value << " ";
        }
        os << "\naccount:";
        for (auto& i : r.accounts)
        {
            os << i.value << " ";
        }
        os << "\npassword:" << r.password.value;
        return os;
    }

    class Connect
    {
    public:
        int id;
        string keys;
        string accounts;
        int password;

        Connect() : id(0), password(0) {}

        bool operator<(Connect& c)
        {
            return this->id < c.id;
        }

        bool operator==(Connect& c)
        {
            return this->id == c.id;
        }

        friend ostream& operator<<(ostream& os, const Connect& c);
    };

    ostream& operator<<(ostream& os, const Connect& c)
    {
        return os;
    }

    template<class T>
    class Result final {
        vector<T>* stack;
    public:
        explicit Result(int num = 0)
        {
            stack = new vector<T>(num);
        }
        Result(const Result& res)
        {
            stack = new vector<T>(res.get_result().begin(), res.get_result().end());
        }
        ~Result()
        {
            stack->clear();
            delete stack;
        }
        int size() const
        {
            return stack->size();
        }
        void push_back(T& val) const
        {
            stack->push_back(val);
        }
        vector<T>& get_result() const
        {
            return *stack;
        }
        bool empty() const {
            return stack->size() == 0;
        }
        void clear() const {
            stack->clear();
        }
        T& toElement() {
            if (stack->size() == 1)
            {
                return stack->at(0);
            }
            else if (stack->size() == 0)
            {
                throw "can't find one element.\n";
            }
            else
            {
                throw "more than one element.\n";
            }
        }
        void print_result() {
            for (auto& i : *stack)
            {
                std::cout << i << std::endl;
            }
        }
    };

    template<class T>
    class UpdateResult {
        Result<T>* res;
    public:
        UpdateResult() {
            res = new Result[2];
        }
        ~UpdateResult() {
            delete res;
        }
        Result<T>*& getOld() {
            return res[0];
        }
        Result<T>*& getNew() {
            return res[1];
        }
    };
}

#endif
